
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>前后端分离认证方式 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>前后端分离认证方式 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">“认证”(Authentication) 和 “授权”(Authorization) 的核心区别是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">认证的核心是验证当前用户的身份，即证明“你是你自己”，例如通过账号密码登录。而授权是在用户认证通过后，根据其权限来控制用户对资源的访问，例如VIP用户可以查看普通用户无法访问的资源。</div>
          </div>
          <div class="card-source">来源: 认证/授权的基本概念</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">请描述基于 Session 的认证机制的工作流程。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">用户认证成功后，服务端会生成与用户相关的数据并保存在服务端的会话(session)中，同时将一个唯一的 SessionId 发送给客户端（通常存放在Cookie中）。之后客户端每次请求都会携带这个 SessionId，服务端通过验证该 ID 来确认用户身份并维持登录状态。</div>
          </div>
          <div class="card-source">来源: 基于Session认证</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">特性</div>
          <div class="card-question">相比基于Token的认证，Session认证在服务集群环境下会遇到什么问题？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">特性</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">Session 数据存储在服务器端，在服务集群的情况下，为了保证用户在不同服务器之间的会话连续性，需要同步各个服务器的session状态，这增加了系统的复杂性。</div>
          </div>
          <div class="card-source">来源: 三者的特点 - Session</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">什么是 OAuth2？它的主要应用场景是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">OAuth2 是一种开放授权标准。其主要应用场景是允许第三方应用在获得用户明确授权的情况下，访问该用户在某个平台（如QQ、百度）上受保护的资源信息，而无需将用户的密码提供给第三方应用。</div>
          </div>
          <div class="card-source">来源: 基于OAuth2认证</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">双 Token 机制是什么？它主要为了解决什么问题？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">双 Token 机制是指服务器在用户登录时生成两个Token：一个有效期较短的 access_token 用于日常的资源访问，和一个有效期较长的 refresh_token 用于刷新 access_token。它主要解决了当 access_token 过期时，用户仍在活跃状态下需要重新登录的问题，通过自动刷新 access_token 提升了用户体验。</div>
          </div>
          <div class="card-source">来源: 双Token机制</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">模式</div>
          <div class="card-question">为什么说使用 refresh_token 可以在一定程度上提升安全性？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">模式</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">因为 access_token 的有效期可以设置得非常短，即使被盗用，攻击者可利用的时间也有限。而 refresh_token 只在刷新 access_token 时才会在网络中传输，传输频率远低于 access_token，因此被盗的风险也远小于 access_token。</div>
          </div>
          <div class="card-source">来源: refresh token</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">在单 Token 认证的实现中，当服务端接收到登录请求并验证成功后，会执行哪几个关键步骤来生成和返回 Token？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">1. 登录验证成功，获取用户信息。 2. 创建并封装一个包含用户ID、用户名、IP地址、登录时间、过期时间等信息的 LoginUser 对象。 3. 将 LoginUser 对象以 Token 为键存入 Redis 中。 4. 使用 JWT 等技术，将部分核心信息（如 token, username, id）封装生成一个最终的 JWT Token 字符串，并返回给客户端。</div>
          </div>
          <div class="card-source">来源: 登录的实现流程</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在双 Token 机制下，当前端请求接口时发现 access_token 已过期（例如收到状态码4001），前端应该如何处理以实现无感刷新？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">当前端收到表示 access_token 失效的响应时，它应自动发起一个携带 refresh_token 的请求去刷新 access_token。如果刷新成功，前端会保存新的 access_token，然后重新执行之前失败的请求。如果刷新失败（refresh_token也已过期），则引导用户跳转到登录页面。</div>
          </div>
          <div class="card-source">来源: 5、accessToken过期后使用refreshToken刷新</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">什么是“会话”(Session)？为什么在认证通过后需要保持会话？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">“会话”是指在用户认证通过后，为了避免用户的每次操作都重新进行认证，系统需要保持一个用户认证状态的机制。常见的会话机制有 session 认证和 token 认证。</div>
          </div>
          <div class="card-source">来源: 什么是会话</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
